﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="TestSetAt.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.Tests.CrsSparseMatrixTest
{
    #region Usings

    using System;

    using ExulLibrary.Exceptions;
    using ExulLibrary.Mathematics.LinearAlgebra.Exceptions;

    using NUnit.Framework;

    #endregion

    /// <summary>
    ///     Test suite for <see cref="CrsSparseMatrixExtensions.SetAt{T}"/>.
    /// </summary>
    [TestFixture]
    [Category("ExulLibrary.Mathematics.LinearAlgebra.Sequential.CrsSparseMatrixExtensions")]
    public sealed class TestSetAt
    {
        /// <summary>
        ///     Tests the method when rowIndex and columnIndex parameters specifies the existing element.
        /// </summary>
        /// <param name="rowIndex">
        ///     The zero-based index of row of the element to set.
        /// </param>
        /// <param name="columnIndex">
        ///     The zero-based index of column of the element to set.
        /// </param>
        /// <param name="elementIndex">
        ///     The zero-based index of the element in the internal storage of the matrix.
        /// </param>
        [Test]
        [TestCase(0, 0, 0)]
        [TestCase(0, 2, 1)]
        [TestCase(1, 0, 2)]
        [TestCase(1, 1, 3)]
        public void WhenIndexesAreValidForExistingElements(int rowIndex, int columnIndex, int elementIndex)
        {
            // Arrange
            // Matrix:
            // 1 0 2
            // 3 4 0
            var matrix = new CrsSparseMatrix<int>(
                rowsCount: 2,
                columnsCount: 3,
                rowsBegins: new[] { 0, 2, 4 },
                columnsIndexes: new[] { 0, 2, 0, 1 });

            // Act
            matrix.SetAt(1, rowIndex, columnIndex);

            // Assert
            Assert.That(matrix.Values[elementIndex], Is.EqualTo(1));
        }

#if !SAFE

        /// <summary>
        ///     Tests the method when rowIndex and columnIndex parameters specifies an element that
        ///     is not in the portrait of the matrix.
        /// </summary>
        /// <param name="rowIndex">
        ///     The zero-based index of row of the element to set.
        /// </param>
        /// <param name="columnIndex">
        ///     The zero-based index of column of the element to set.
        /// </param>
        [Test]
        [TestCase(0, 1)]
        [TestCase(1, 2)]
        public void WhenIndexesAreValidForExistingElements(int rowIndex, int columnIndex)
        {
            // Arrange
            // Matrix:
            // 1 0 2
            // 3 4 0
            var matrix = new CrsSparseMatrix<int>(
                rowsCount: 2,
                columnsCount: 3,
                rowsBegins: new[] { 0, 2, 4 },
                columnsIndexes: new[] { 0, 2, 0, 1 });

            // Act
            matrix.SetAt(1, rowIndex, columnIndex);

            // Assert
            Assert.That(matrix.Values, Has.All.EqualTo(0));
        }

#endif

#if SAFE

        /// <summary>
        ///     Tests the method when rowIndex and columnIndex parameters specifies an element that
        ///     is not in the portrait of the matrix.
        /// </summary>
        /// <param name="rowIndex">
        ///     The zero-based index of row of the element to set.
        /// </param>
        /// <param name="columnIndex">
        ///     The zero-based index of column of the element to set.
        /// </param>
        [Test]
        [TestCase(0, 1)]
        [TestCase(1, 2)]
        public void WhenIndexesAreValidForExistingElements(int rowIndex, int columnIndex)
        {
            // Arrange
            // Matrix:
            // 1 0 2
            // 3 4 0
            var matrix = new CrsSparseMatrix<int>(
                rowsCount: 2,
                columnsCount: 3,
                rowsBegins: new[] { 0, 2, 4 },
                columnsIndexes: new[] { 0, 2, 0, 1 });

            // Act and Assert
            Assert.That(
                () => matrix.SetAt(1, rowIndex, columnIndex),
                Throws.TypeOf<ReadOnlyMatrixElementException>().With.Property("ParamName").EqualTo("matrix"));
        }

        /// <summary>
        ///     Tests the method when rowIndex parameter is negative or greater than or equal to rows count of the matrix.
        /// </summary>
        /// <param name="rowIndex">
        ///     The row index of the element to set.
        /// </param>
        [Test]
        public void WhenRowIndexIsOutOfRange([Values(-1, 2)] int rowIndex)
        {
            // Arrange
            // Matrix:
            // 1 0 2
            // 3 4 0
            var matrix = new CrsSparseMatrix<int>(
                rowsCount: 2,
                columnsCount: 3,
                rowsBegins: new[] { 0, 2, 4 },
                columnsIndexes: new[] { 0, 2, 0, 1 });

            // Act and Assert
            Assert.That(
                () => matrix.SetAt(1, rowIndex, 0),
                Throws.TypeOf<ElementIndexIsOutOfRangeException>().With.Property("ParamName").EqualTo("rowIndex"));
        }

        /// <summary>
        ///     Tests the method when columnIndex parameter is negative or greater than or equal to columns count of the matrix.
        /// </summary>
        /// <param name="columnIndex">
        ///     The column index of the element to set.
        /// </param>
        [Test]
        public void WhenColumnIndexIsOutOfRange([Values(-1, 3)] int columnIndex)
        {
            // Arrange
            // Matrix:
            // 1 0 2
            // 3 4 0
            var matrix = new CrsSparseMatrix<int>(
                rowsCount: 2,
                columnsCount: 3,
                rowsBegins: new[] { 0, 2, 4 },
                columnsIndexes: new[] { 0, 2, 0, 1 });

            // Act and Assert
            Assert.That(
                () => matrix.SetAt(1, 0, columnIndex),
                Throws.TypeOf<ElementIndexIsOutOfRangeException>().With.Property("ParamName").EqualTo("columnIndex"));
        }

        /// <summary>
        ///     Tests the method when matrix parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenMatrixIsNull()
        {
            // Act and Assert
            Assert.That(
                () => CrsSparseMatrixExtensions.SetAt(null, 1, 0, 0),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("matrix"));
        }

#endif
    }
}